//
// Created by Guoshun WU on 2021/2/27.
//

#ifndef AVSTUDY_SMARTPOINTER_H
#define AVSTUDY_SMARTPOINTER_H

#include "Log.h"
#include <mutex>

using namespace std;

template<typename T>
class SmartPointer {
    T *_t = nullptr;
    int counter = 0;
    mutex lock;

    void freeMe() {
        lock_guard<mutex> guard(lock);
        if (nullptr == _t) return;

        if (0 == --counter) {
            logDebug("About to free _t");
            delete _t;
        } else {
            logDebug("counter=%d", counter);
        }
    }

public:
    explicit SmartPointer(T *t = nullptr) : _t(t) {
        if (nullptr == t) {
            return;
        }
        ++counter;
        logDebug("counter=%d", counter);
    }

    SmartPointer(const SmartPointer &ptr) {

        counter = ptr.counter;
        _t = ptr._t;
        if (ptr._t) ++counter;

        logDebug("counter=%d", counter);
    }

    bool operator==(const SmartPointer &ptr) {
        return _t == ptr._t;
    }

    SmartPointer &operator=(const SmartPointer &ptr) {
        if (this == &ptr) {
            return *this;
        }
        ++counter;
        freeMe();
        counter = ptr.counter;
        _t = ptr._t;


        return *this;
    }

    ~SmartPointer() {
        freeMe();
    }

    T &operator*() {
        if (nullptr == _t) {
            throw "null pointer exception";
        }
        return *_t;
    }

    T *operator->() {
        return _t;
    }

    int use_count() {
        return counter;
    }
};

#endif //AVSTUDY_SMARTPOINTER_H
